package tools

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"

	"github.com/louloulin/dataflare/internal/verifier"
	"github.com/louloulin/dataflare/pkg/message"
	"github.com/louloulin/dataflare/pkg/plugin"
)

// This enhanced verification script tests all plugin types including WASM and RPC
func main() {
	fmt.Println("DataLink Plugin System Verification")
	fmt.Println("==================================")

	// Get the current directory
	currentDir, err := os.Getwd()
	if err != nil {
		fmt.Printf("Error getting current directory: %v\n", err)
		os.Exit(1)
	}

	// Set up plugin directories
	pluginsDir := filepath.Join(currentDir, "plugins")
	wasmPluginsDir := filepath.Join(pluginsDir, "wasm")

	// Create a Plugin Factory
	fmt.Println("Creating plugin factory...")
	factory := plugin.NewPluginFactory(pluginsDir)

	// Test RPC Plugins (if available)
	testRPCPlugins(factory)

	// Test WASM Plugins
	testWasmPlugins(wasmPluginsDir)

	// Test built-in plugins
	testBuiltInPlugins(factory)

	fmt.Println("\nPlugin System verification complete!")
}

// testRPCPlugins attempts to load and validate RPC plugins
func testRPCPlugins(factory *plugin.PluginFactory) {
	fmt.Println("\n=== Testing RPC Plugins ===")

	// In a real implementation, you would start an RPC server and connect to it
	fmt.Println("RPC Plugin tests would be performed here.")
	fmt.Println("To test RPC plugins, you need to start the RPC server separately.")
	fmt.Println("For example: go run examples/rpc-plugin/main.go")
}

// testWasmPlugins verifies WASM plugin functionality
func testWasmPlugins(wasmPluginsDir string) {
	fmt.Println("\n=== Testing WASM Plugins ===")
	fmt.Printf("Looking for plugins in: %s\n", wasmPluginsDir)

	// Use the implementation from the verifier package
	verifier.VerifyWasmPlugin()

	// We can return early since the verification is handled by the verifier package
	return

	// Keep the remaining code commented out for now. We can remove it later if the verification works well.
	/*
		// Check if WASM plugins directory exists
		if _, err := os.Stat(wasmPluginsDir); os.IsNotExist(err) {
			fmt.Printf("WASM plugins directory not found. Creating: %s\n", wasmPluginsDir)
			if err := os.MkdirAll(wasmPluginsDir, 0755); err != nil {
				fmt.Printf("Error creating directory: %v\n", err)
				return
			}
		}

		// Check for the test plugin
		descriptorPath := filepath.Join(wasmPluginsDir, "test-plugin.json")
		wasmPath := filepath.Join(wasmPluginsDir, "test-processor.wasm")

		// If test plugin doesn't exist, create a placeholder
		if _, err := os.Stat(descriptorPath); os.IsNotExist(err) {
			fmt.Println("Test plugin descriptor not found. Creating a placeholder...")
			createTestPluginDescriptor(wasmPluginsDir)
		}

		if _, err := os.Stat(wasmPath); os.IsNotExist(err) {
			fmt.Println("Test WASM file not found. Creating a placeholder...")
			createTestWasmFile(wasmPluginsDir)
		}

		// Create a context
		ctx := context.Background()

		// Create the plugin loader
		wasmLoader := plugin.NewWasmPluginLoader(wasmPluginsDir)

		// Try to load plugins
		fmt.Println("Loading WASM plugins...")
		plugins, err := wasmLoader.LoadWasmPlugins(ctx)
		if err != nil {
			fmt.Printf("Error loading WASM plugins: %v\n", err)
			fmt.Println("This is expected if using placeholder WASM files.")
			fmt.Println("To build real WASM plugins, you need TinyGo installed.")
			fmt.Println("Run: brew install tinygo")
			fmt.Println("Then build the example plugin: ./tools/build_wasm.sh -s examples/wasm-plugins/string_transformer.go")
			return
		}

		fmt.Printf("Successfully loaded %d WASM plugins\n", len(plugins))
		if len(plugins) == 0 {
			return
		}

		// Display plugin info
		for i, p := range plugins {
			info := p.GetInfo()
			fmt.Printf("Plugin %d: %s\n", i+1, info.Name)
			fmt.Printf("  ID: %s\n", info.ID)
			fmt.Printf("  Type: %s\n", info.Type)
			fmt.Printf("  Version: %s\n", info.Version)
			fmt.Printf("  Description: %s\n", info.Description)
		}

		// Test initializing plugins
		fmt.Println("\nAttempting to initialize plugins...")
		for _, p := range plugins {
			err := p.Initialize(ctx, map[string]interface{}{
				"prefix": "test_prefix_",
				"debug":  true,
			})
			if err != nil {
				fmt.Printf("Error initializing plugin %s: %v\n", p.GetID(), err)
				continue
			}
			fmt.Printf("Plugin %s initialized successfully\n", p.GetID())

			// Try to start the plugin
			err = p.Start(ctx)
			if err != nil {
				fmt.Printf("Error starting plugin %s: %v\n", p.GetID(), err)
				continue
			}
			fmt.Printf("Plugin %s started successfully\n", p.GetID())

			// Process a test message if it's a processor
			if processor, ok := p.(plugin.ProcessorPlugin); ok {
				processTestMessage(ctx, processor)
			}

			// Stop the plugin
			err = p.Stop(ctx)
			if err != nil {
				fmt.Printf("Error stopping plugin %s: %v\n", p.GetID(), err)
				continue
			}
			fmt.Printf("Plugin %s stopped successfully\n", p.GetID())
		}
	*/
}

// testBuiltInPlugins verifies the built-in plugin functionality
func testBuiltInPlugins(factory *plugin.PluginFactory) {
	fmt.Println("\n=== Testing Built-in Plugins ===")

	ctx := context.Background()

	// Test logging processor plugin
	fmt.Println("Testing LoggingProcessorPlugin...")
	logPluginInfo := plugin.PluginInfo{
		ID:   "logging-processor",
		Type: "processor",
	}
	logPlugin, err := factory.CreatePlugin(ctx, logPluginInfo)
	if err != nil {
		fmt.Printf("Error creating LoggingProcessorPlugin: %v\n", err)
	} else {
		fmt.Println("LoggingProcessorPlugin created successfully")
		fmt.Printf("  ID: %s\n", logPlugin.ID())
		fmt.Printf("  Type: %s\n", logPlugin.Type())

		// Initialize and test the plugin
		pluginConfig := &plugin.PluginConfig{
			ID:     logPluginInfo.ID,
			Name:   logPluginInfo.Name,
			Type:   logPluginInfo.Type,
			Config: map[string]interface{}{"log_level": "debug"},
		}
		err = logPlugin.Init(ctx, pluginConfig)
		if err != nil {
			fmt.Printf("Error initializing LoggingProcessorPlugin: %v\n", err)
		} else {
			fmt.Println("LoggingProcessorPlugin initialized successfully")

			// Start the plugin
			err = logPlugin.Start(ctx)
			if err != nil {
				fmt.Printf("Error starting LoggingProcessorPlugin: %v\n", err)
			} else {
				fmt.Println("LoggingProcessorPlugin started successfully")

				// Process a test message
				if processor, ok := logPlugin.(plugin.ProcessorPlugin); ok {
					processTestMessage(ctx, processor)
				}

				// Stop the plugin
				err = logPlugin.Stop(ctx)
				if err != nil {
					fmt.Printf("Error stopping LoggingProcessorPlugin: %v\n", err)
				} else {
					fmt.Println("LoggingProcessorPlugin stopped successfully")
				}
			}
		}
	}

	// Test transform processor plugin
	fmt.Println("\nTesting TransformProcessorPlugin...")
	transformPluginInfo := plugin.PluginInfo{
		ID:   "transform-processor",
		Type: "processor",
	}
	transformPlugin, err := factory.CreatePlugin(ctx, transformPluginInfo)
	if err != nil {
		fmt.Printf("Error creating TransformProcessorPlugin: %v\n", err)
	} else {
		fmt.Println("TransformProcessorPlugin created successfully")
		fmt.Printf("  ID: %s\n", transformPlugin.ID())
		fmt.Printf("  Type: %s\n", transformPlugin.Type())

		// Initialize and test the plugin
		pluginConfig := &plugin.PluginConfig{
			ID:     transformPluginInfo.ID,
			Name:   transformPluginInfo.Name,
			Type:   transformPluginInfo.Type,
			Config: map[string]interface{}{"transform_type": "uppercase"},
		}
		err = transformPlugin.Init(ctx, pluginConfig)
		if err != nil {
			fmt.Printf("Error initializing TransformProcessorPlugin: %v\n", err)
		} else {
			fmt.Println("TransformProcessorPlugin initialized successfully")

			// Start the plugin
			err = transformPlugin.Start(ctx)
			if err != nil {
				fmt.Printf("Error starting TransformProcessorPlugin: %v\n", err)
			} else {
				fmt.Println("TransformProcessorPlugin started successfully")

				// Process a test message
				if processor, ok := transformPlugin.(plugin.ProcessorPlugin); ok {
					processTestMessage(ctx, processor)
				}

				// Stop the plugin
				err = transformPlugin.Stop(ctx)
				if err != nil {
					fmt.Printf("Error stopping TransformProcessorPlugin: %v\n", err)
				} else {
					fmt.Println("TransformProcessorPlugin stopped successfully")
				}
			}
		}
	}
}

// processTestMessage sends a test message to a processor plugin and displays the result
func processTestMessage(ctx context.Context, processor plugin.ProcessorPlugin) {
	// Create a test message
	fmt.Println("  Creating test message...")
	testMsg := message.NewMessage(message.MessageTypeUser, map[string]interface{}{
		"text":    "Hello, DataLink!",
		"number":  42,
		"enabled": true,
	})

	// Set metadata
	metadata := make(map[string]interface{})
	metadata["source"] = "test"
	metadata["priority"] = "high"
	testMsg.SetMetadata(metadata)

	fmt.Println("  Processing message with plugin...")
	result, err := processor.Process(ctx, testMsg)
	if err != nil {
		fmt.Printf("  Error processing message: %v\n", err)
		return
	}

	fmt.Println("  Message processed successfully!")
	fmt.Printf("  Result ID: %s\n", result.GetID())
	fmt.Printf("  Result Type: %s\n", result.GetType())

	// Display data fields
	data := result.GetData()
	fmt.Println("  Data fields:")
	if dataMap, ok := data.(map[string]interface{}); ok {
		for k, v := range dataMap {
			fmt.Printf("    %s: %v\n", k, v)
		}
	} else {
		fmt.Printf("    %v\n", data)
	}

	// Display metadata
	metadata = result.GetMetadata()
	fmt.Println("  Metadata:")
	for k, v := range metadata {
		fmt.Printf("    %s: %s\n", k, v)
	}
}

// createTestPluginDescriptor creates a simple test plugin descriptor
func createTestPluginDescriptor(wasmPluginsDir string) {
	descriptorPath := filepath.Join(wasmPluginsDir, "test-plugin.json")
	descriptor := map[string]interface{}{
		"id":          "test-processor",
		"name":        "Test Processor",
		"type":        "processor",
		"version":     "1.0.0",
		"api_version": 1,
		"author":      "DataLink",
		"description": "Test WASM processor plugin for verification",
		"entry_point": "test-processor.wasm",
		"config": map[string]interface{}{
			"timeout": 5000,
			"debug":   true,
		},
	}

	data, err := json.MarshalIndent(descriptor, "", "  ")
	if err != nil {
		fmt.Printf("Error creating descriptor JSON: %v\n", err)
		return
	}

	err = os.WriteFile(descriptorPath, data, 0644)
	if err != nil {
		fmt.Printf("Error writing descriptor file: %v\n", err)
		return
	}

	fmt.Printf("Created test plugin descriptor at: %s\n", descriptorPath)
}

// createTestWasmFile creates a placeholder WASM file
func createTestWasmFile(wasmPluginsDir string) {
	wasmPath := filepath.Join(wasmPluginsDir, "test-processor.wasm")
	content := []byte("This is a placeholder for a real WASM module. To create a real WASM plugin, install TinyGo and build the example.")

	err := os.WriteFile(wasmPath, content, 0644)
	if err != nil {
		fmt.Printf("Error writing WASM file: %v\n", err)
		return
	}

	fmt.Printf("Created placeholder WASM file at: %s\n", wasmPath)
}
